home *** CD-ROM | disk | FTP | other *** search
- /*
- * BSD-style socket emulation library for the Mac
- * Original author: Tom Milligan
- * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
- *
- * This source file is placed in the public domian.
- * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
- *
- * National Center for Supercomputing Applications
- * 152 Computing Applications Building
- * 605 E. Springfield Ave.
- * Champaign, IL 61820
- */
-
- #ifdef USEDUMP
- # pragma load "Socket.dump"
-
- #else
- # include <Events.h>
- # include <Memory.h>
- # include <Types.h>
- # include <OSUtils.h> /* for SysBeep */
- # include <Events.h> /* for TickCount */
- # include <Stdio.h>
-
-
- # include <s_types.h>
- # include <neti_in.h>
- #ifdef COMP_CODEWAR
- #define NOWAY
- #undef EDOM
- #undef ERANGE
- #endif
- # include <neterrno.h>
- # include <s_socket.h>
- # include <s_time.h>
- # include <s_uio.h>
-
- # include "sock_str.h"
- # include "sock_int.h"
- # include <unixlib.h>
-
- #endif
-
- #ifndef THINK_C
- # include "sock_int.h"
- #endif
-
- extern SocketPtr sockets;
- extern SpinFn spinroutine; /* The spin routine. */
-
- /*
- * sock_tcp_new_stream
- *
- * Create a new tcp stream.
- */
- int sock_tcp_new_stream(
- SocketPtr sp)
- {
- OSErr io;
- TCPiopb pb;
- StreamHashEntPtr shep;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_new_stream", sp);
- #endif
-
- io = xTCPCreate(STREAM_BUFFER_SIZE, sock_tcp_notify, &pb);
- switch(io)
- {
- case noErr: break;
- case streamAlreadyOpen: return(sock_err(io));
- case invalidLength: return(sock_err(ENOBUFS));
- case invalidBufPtr: return(sock_err(ENOBUFS));
- case insufficientResources: return(sock_err(EMFILE));
- default: /* error from PBOpen */ return(sock_err(ENETDOWN));
- }
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->peer.sin_family = AF_INET;
- sp->peer.sin_addr.s_addr = 0;
- sp->peer.sin_port = 0;
- bzero(&sp->peer.sin_zero[0], 8);
- sp->dataavail = 0;
- sp->asyncerr = 0;
- sp->stream = pb.tcpStream;
-
- if ((shep = sock_new_shep(sp->stream))!=NULL)
- {
- shep -> stream = sp->stream;
- shep -> socket = sp;
- return(0);
- }
- else
- return -1;
- }
-
-
- /*
- * sock_tcp_connect - initiate a connection on a TCP socket
- *
- */
- static void sock_tcp_connect_done(TCPiopb *pb);
-
- int sock_tcp_connect(
- SocketPtr sp,
- struct sockaddr_in *addr)
- {
- OSErr io;
- TCPiopb *pb;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_connect",sp);
- #endif
-
- /* Make sure this socket can connect. */
- if (sp->sstate == SOCK_STATE_CONNECTING)
- return(sock_err(EALREADY));
- if (sp->sstate != SOCK_STATE_UNCONNECTED)
- return(sock_err(EISCONN));
-
- sp->sstate = SOCK_STATE_CONNECTING;
-
- if (!(pb= (TCPiopb *)sock_fetch_pb(sp)))
- return sock_err(ENOMEM);
-
- io = xTCPActiveOpen(pb, sp->sa.sin_port,addr->sin_addr.s_addr, addr->sin_port,
- (TCPIOCompletionProc) sock_tcp_connect_done);
-
- if (io != noErr)
- {
- sp->sstate = SOCK_STATE_UNCONNECTED;
- return(sock_err(io));
- }
-
- if (sp->nonblocking)
- return(sock_err(EINPROGRESS));
-
- /* sync connect - spin till TCPActiveOpen completes */
-
- #if SOCK_TCP_DEBUG >= 5
- dprintf("spinning in connect\n");
- #endif
-
- SPIN (pb->ioResult==inProgress,SP_MISC,0L)
-
- #if SOCK_TCP_DEBUG >= 5
- dprintf("done spinning\n");
- #endif
-
- if ( pb->ioResult != noErr )
- return sock_err(pb->ioResult);
- else
- return 0;
- }
-
- static void sock_tcp_listen_done(TCPiopb *pb)
- {
- SocketPtr sp;
-
- sp = sock_find_shep(pb->tcpStream)->socket;
-
- switch(pb->ioResult)
- {
- case noErr:
- sp->peer.sin_addr.s_addr = pb->csParam.open.remoteHost;
- sp->peer.sin_port = pb->csParam.open.remotePort;
- sp->sstate = SOCK_STATE_LIS_CON;
- sp->asyncerr = 0;
- break;
-
- case openFailed:
- case invalidStreamPtr:
- case connectionExists:
- case duplicateSocket:
- case commandTimeout:
- default:
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->asyncerr = pb->ioResult;
- break;
- }
- }
-
- /*
- * sock_tcp_listen() - put s into the listen state.
- */
- int sock_tcp_listen(
- SocketPtr sp)
- {
- OSErr io;
- TCPiopb *pb;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_listen",sp);
- #endif
-
- if (!(pb = (TCPiopb *)sock_fetch_pb(sp)))
- return (sock_err(ENOMEM));
-
- if (sp->sstate != SOCK_STATE_UNCONNECTED)
- return(sock_err(EISCONN));
-
- sp->sstate = SOCK_STATE_LISTENING;
-
- io = xTCPPassiveOpen(pb, sp->sa.sin_port,
- (TCPIOCompletionProc) sock_tcp_listen_done);
- if (io != noErr)
- {
- sp->sstate = SOCK_STATE_UNCONNECTED;
- return(sock_err(io));
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_listen: about to spin for port number - ticks %d\n",
- TickCount());
- #endif
- while (pb->csParam.open.localPort == 0)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- SPIN(false,SP_MISC,0L)
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_listen: port number is %d ticks %d\n",
- pb->csParam.open.localPort,TickCount());
- #endif
- sp->sa.sin_addr.s_addr = pb->csParam.open.localHost;
- sp->sa.sin_port = pb->csParam.open.localPort;
- return(0);
- }
-
- /*
- * sock_tcp_accept()
- */
- int sock_tcp_accept(
- SocketPtr sp,
- struct sockaddr_in *from,
- Int4 *fromlen)
- {
- int s1;
- TCPiopb *pb;
- StreamHashEntPtr shep;
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_accept",sp);
- #endif
-
- if (sp->sstate == SOCK_STATE_UNCONNECTED)
- {
- if (sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- else
- return(sock_err(ENOTCONN));
- }
- if (sp->sstate != SOCK_STATE_LISTENING && sp->sstate != SOCK_STATE_LIS_CON)
- return(sock_err(ENOTCONN));
-
- if (sp->sstate == SOCK_STATE_LISTENING)
- {
- if (sp->nonblocking)
- return(sock_err(EWOULDBLOCK));
-
- /* Spin till sock_tcp_listen_done runs. */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("--- blocking...\n");
- #endif
-
- SPIN(sp->sstate == SOCK_STATE_LISTENING,SP_MISC,0L);
-
- #if SOCK_TCP_DEBUG >= 5
- dprintf("--- done blocking...\n");
- #endif
-
- /* got notification - was it success? */
- if (sp->sstate != SOCK_STATE_LIS_CON)
- {
- #if SOCK_TCP_DEBUG >=3
- dprintf("--- failed state %04x code %d\n",sp->sstate,sp->asyncerr);
- #endif
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- }
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_accept: Have connection, peer is %08x/%d, duplicating socket.\n",
- sp->peer.sin_addr,sp->peer.sin_port);
- #endif
- /*
- * Have connection. Duplicate this socket. The client gets the connection
- * on the new socket and I create a new stream on the old socket and put it
- * in listen state.
- */
- sp->sstate = SOCK_STATE_CONNECTED;
-
- s1 = sock_free_fd(0);
- if (s1 < 0)
- {
- /* No descriptors left. Abort the incoming connection. */
- #if SOCK_TCP_DEBUG >= 2
- dprintf("sock_tcp_accept: No descriptors left.\n");
- #endif
- if (!(pb = (TCPiopb *)sock_fetch_pb (sp)))
- return sock_err(ENOMEM);
-
- (void) xTCPAbort(pb);
- sp->sstate = SOCK_STATE_UNCONNECTED;
-
- /* try and put the socket back in listen mode */
- if (sock_tcp_listen(sp) < 0)
- {
- #if SOCK_TCP_DEBUG >= 1
- dprintf("sock_tcp_accept: sock_tcp_listen fails\n");
- #endif
- sp->sstate = SOCK_STATE_UNCONNECTED;
- return(-1); /* errno already set */
- }
- return(sock_err(EMFILE));
- }
-
- /* copy the incoming connection to the new socket */
- sock_dup_fd(sp->fd,s1);
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_accept: new socket is %d\n",s1);
- sock_dump();
- #endif
-
- /* quitely adjust the StreamHash table */
- if ((shep = sock_find_shep(sp->stream))!=NULL)
- {
- shep->socket = sockets+s1; /* point to new socket */
- }
-
- /* Create a new MacTCP stream on the old socket and put it into */
- /* listen state to accept more connections. */
- if (sock_tcp_new_stream(sp) < 0 || sock_tcp_listen(sp) < 0)
- {
- #if SOCK_TCP_DEBUG >= 2
- dprintf("accept: failed to restart old socket\n");
- #endif
- /* nothing to listen on */
- sp->sstate = SOCK_STATE_UNCONNECTED;
-
- /* kill the incoming connection */
- if (!(pb= (TCPiopb *)sock_fetch_pb(sockets+s1)))
- return sock_err(ENOMEM);
-
- xTCPRelease(pb);
- sock_clear_fd(s1);
-
- return(-1); /* errno set */
- }
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_accept: got new stream\n");
- sock_dump();
- #endif
-
- /* return address of partner */
- sock_copy_addr(&sockets[s1].peer, from, fromlen);
-
- return(s1);
- }
-
- /*
- * sock_tcp_accept_once()
- */
- int sock_tcp_accept_once(
- SocketPtr sp,
- struct sockaddr_in *from,
- Int4 *fromlen)
- {
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_accept_once",sp);
- #endif
-
- if (sp->sstate == SOCK_STATE_UNCONNECTED)
- {
- if (sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- else
- return(sock_err(ENOTCONN));
- }
- if (sp->sstate != SOCK_STATE_LISTENING && sp->sstate != SOCK_STATE_LIS_CON)
- return(sock_err(ENOTCONN));
-
- if (sp->sstate == SOCK_STATE_LISTENING)
- {
- if (sp->nonblocking)
- return(sock_err(EWOULDBLOCK));
-
- /* Spin till sock_tcp_listen_done runs. */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("--- blocking...\n");
- #endif
-
- SPIN(sp->sstate == SOCK_STATE_LISTENING,SP_MISC,0L);
-
- #if SOCK_TCP_DEBUG >= 5
- dprintf("--- done blocking...\n");
- #endif
-
- /* got notification - was it success? */
- if (sp->sstate != SOCK_STATE_LIS_CON)
- {
- #if SOCK_TCP_DEBUG >=3
- dprintf("--- failed state %04x code %d\n",sp->sstate,sp->asyncerr);
- #endif
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
- }
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_accept_once: Have connection, peer is %08x/%d.\n",
- sp->peer.sin_addr,sp->peer.sin_port);
- #endif
- /*
- * Have connection.
- */
- sp->sstate = SOCK_STATE_CONNECTED;
-
- /* return address of partner */
- sock_copy_addr(&(sp->peer), from, fromlen);
-
- return(0);
- }
-
-
- static void sock_tcp_recv_done( TCPiopb *pb);
-
- /*
- * sock_tcp_recv()
- *
- * returns bytes received or -1 and errno
- */
- int sock_tcp_recv(
- SocketPtr sp,
- char *buffer,
- int buflen,
- int flags)
- {
- #pragma unused(flags)
- TCPiopb *pb;
- int iter; /* iteration */
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_recv",sp);
- #endif
-
- /* socket hasn't finished connecting yet */
- if (sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: connection still in progress\n");
- #endif
- if (sp->nonblocking)
- return(sock_err(EWOULDBLOCK));
-
- /* async connect and sync recv? */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: spinning on connect\n");
- #endif
-
- SPIN(sp->sstate == SOCK_STATE_CONNECTING,SP_MISC,0L)
-
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_recv: done spinning\n");
- #endif
- }
-
- /* socket is not connected */
- if (! (sp->sstate == SOCK_STATE_CONNECTED))
- {
- /* see if the connect died (pretty poor test) */
- if (sp->sstate == SOCK_STATE_UNCONNECTED && sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
-
- /* I guess he just forgot */
- return(sock_err(ENOTCONN));
- }
-
- if (sp->dataavail == 0)
- sp->dataavail = xTCPBytesUnread(sp); /* sync. call */
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_recv: %d bytes available\n", sp->dataavail);
- #endif
- if (sp->nonblocking && sp->dataavail == 0)
- return(sock_err(EWOULDBLOCK));
-
- sp->torecv = 1; /* # of bytes to try to receive */
- sp->recvBuf = buffer;
- sp->recvd = 0; /* count of bytes received */
- pb = (TCPiopb *)sock_fetch_pb(sp);
-
- /* make 2 iterations; on 1st try, read 1 byte; on 2nd, read
- all outstanding available bytes, up to buflen ... this mechanism seems to
- be necessary for decent performance, because TCPRcv only completes when one
- of the following takes place:
- * enough data has arrived to fill the receive buffer
- * pushed data arrives
- * urgent data is outstanding
- * some reasonable period passes after the arrival of nonpushed, nonurgent data
- * the amount of data received is greater than or equal to 25 percent of the total
- receive buffering for this stream
- * the command time-out expires
-
- In the case when a caller has requested N bytes, and the data is "normal" TCP
- data, the "reasonable" period must expire before this function will return. This
- "reasonable" period appears to be about one second (MacTCP version 1.1), and is
- not configurable. The hope in the algorithm implemented here is that a reasonable
- amount of data will arrive along with the first byte, and that the caller is
- capable of issuing another read() to obtain more data. The one-second "reasonable"
- delay is thus eliminated.
-
- J. Epstein, NCBI, 06/24/92
- */
-
- for (iter = 0; iter < 2; iter++) {
-
- sp->asyncerr = inProgress;
-
- xTCPRcv(pb, sp->recvBuf, min (sp->torecv,TCP_MAX_MSG),0,
- (TCPIOCompletionProc) sock_tcp_recv_done);
-
- SPIN(sp->torecv&&(pb->ioResult==noErr||pb->ioResult==inProgress),
- SP_TCP_READ,sp->torecv)
-
- if ( pb->ioResult == commandTimeout )
- pb->ioResult = noErr;
-
- switch(pb->ioResult)
- {
- case noErr:
- #if SOCK_TCP_DEBUG >= 3
- dprintf("sock_tcp_recv: got %d bytes\n", sp->recvd);
- #endif
- sp->dataavail = xTCPBytesUnread(sp);
- sp->asyncerr = noErr;
- if (sp->dataavail <= 0 || buflen <= 1 || iter == 1)
- return(sp->recvd);
- /* loop back and obtain the remaining outstanding data */
- sp->torecv = min(sp->dataavail, buflen - 1);
- sp->recvBuf = &buffer[1];
- break;
-
- case connectionClosing:
- #if SOCK_TCP_DEBUG >= 2
- dprintf("sock_tcp_recv: connection closed\n");
- #endif
- return (sp->recvd);
- break;
-
-
- case connectionTerminated:
- /* The connection is aborted. */
- sp->sstate = SOCK_STATE_UNCONNECTED;
- #if SOCK_TCP_DEBUG >= 1
- dprintf("sock_tcp_recv: connection gone!\n");
- #endif
- return(sock_err(ENOTCONN));
-
- case commandTimeout: /* this one should be caught by sock_tcp_recv_done */
- case connectionDoesntExist:
- case invalidStreamPtr:
- case invalidLength:
- case invalidBufPtr:
- default:
- return(sock_err(pb->ioResult));
- }
- }
- return(sock_err(ENOTCONN));
- }
-
- /*
- * sock_tcp_can_read() - returns non-zero if data or a connection is available
- * must also return one if the connection is down to force an exit from the
- * select routine (select is the only thing that uses this).
- */
- int sock_tcp_can_read(SocketPtr sp)
- {
- TCPiopb *pb;
-
- if (sp->sstate == SOCK_STATE_LIS_CON)
- return(1);
-
- else if (sp->sstate == SOCK_STATE_CONNECTED)
- {
- if (!(pb= (TCPiopb *)sock_fetch_pb(sp)))
- return sock_err (ENOMEM);
-
- sp->dataavail = xTCPBytesUnread(sp);
- if (sp->dataavail > 0)
- return(1);
- }
- else if ( ( sp->sstate == SOCK_STATE_UNCONNECTED ) ||
- ( sp->sstate == SOCK_STATE_CLOSING ) )
- return 1;
-
- return(0);
- }
-
- /* avoid using standard library here because size of an int may vary externally */
- void *sock_memset(void *s, int c, size_t n)
- {
- char *t = (char*)s;
-
- for (; n > 0; n--, t++)
- *t = c;
- return s;
- }
-
- static void sock_tcp_send_done( TCPiopb *pb);
-
- /*
- * sock_tcp_send() - send data
- *
- * returns bytes sent or -1 and errno
- */
- int sock_tcp_send(
- SocketPtr sp,
- char *buffer,
- int count,
- int flags)
- {
- int bytes,towrite;
- miniwds *thiswds;
- short wdsnum;
- TCPiopb *pb;
- miniwds wdsarray[TCP_MAX_WDS];
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_send",sp);
- #endif
-
- /* socket hasn't finished connecting yet */
- if (sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: connection still in progress\n");
- #endif
- if (sp->nonblocking)
- return(sock_err(EALREADY));
-
- /* async connect and sync send? */
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: spinning on connect\n");
- #endif
- while(sp->sstate == SOCK_STATE_CONNECTING)
- {
- #if SOCK_TCP_DEBUG >= 5
- tcpCheckNotify();
- #endif
- SPIN(false,SP_MISC,0L)
- }
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_send: done spinning\n");
- #endif
- }
-
- /* socket is not connected */
- if (! (sp->sstate == SOCK_STATE_CONNECTED))
- {
- /* see if a previous operation failed */
- if (sp->sstate == SOCK_STATE_UNCONNECTED && sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
-
- /* I guess he just forgot */
- return(sock_err(ENOTCONN));
- }
-
- if ( (xTCPBytesWriteable(sp) < count) && (sp->nonblocking) )
- return sock_err(EWOULDBLOCK);
-
- bytes=count; /* save count before we nuke it */
- sock_memset(wdsarray,0,TCP_MAX_WDS*sizeof(miniwds)); /* clear up terminus and mark empty */
- thiswds = wdsarray;
- wdsnum = 0;
-
- while (count > 0)
- {
- /* make sure the thing that just finished worked ok */
- if (sp->asyncerr != 0)
- {
- (void) sock_err(sp->asyncerr);
- sp->asyncerr = 0;
- return(-1);
- }
-
- /*
- * for deBUGging: try replacing TCP_MAX_MSG with a small value (like 7) so
- * you can test that the loop won't choke while waiting for writes to finish
- */
- towrite=min(count,TCP_MAX_MSG);
-
- /* find a clean wds */
-
- while ( thiswds->length != 0 )
- {
- wdsnum = (short)((wdsnum+1)%TCP_MAX_WDS); /* generates compiler warning w/o short - why? */
- if (wdsnum)
- thiswds++;
- else
- thiswds = wdsarray;
- SPIN(false,SP_TCP_WRITE,count); /* spin once */
- }
-
- /* find a clean pb */
-
- if (!(pb= (TCPiopb *)sock_fetch_pb(sp)))
- return sock_err(ENOMEM);
-
-
- thiswds->length = (short)towrite;
- thiswds->ptr=buffer;
-
- xTCPSend(pb,(wdsEntry *)thiswds,(count <= TCP_MAX_MSG), /* push */
- flags & MSG_OOB, /*urgent*/
- (TCPIOCompletionProc) sock_tcp_send_done);
-
- SPIN(false,SP_TCP_WRITE,count);
- count -= towrite;
- buffer += towrite;
- }
-
- SPIN(pb->ioResult == inProgress,SP_TCP_WRITE,0);
-
- if ( pb->ioResult == noErr )
- {
- return(bytes);
- }
- else
- return(sock_err(pb->ioResult));
- }
-
-
- /*
- * sock_tcp_can_write() - returns non-zero if a write will not block
- * Very lousy check. Need to check (send window)-(unack data).
- */
- int sock_tcp_can_write(
- SocketPtr sp)
- {
- return (sp->sstate == SOCK_STATE_CONNECTED);
- }
-
- /*
- * sock_tcp_close() - close down a socket being careful about i/o in progress
- */
- int sock_tcp_close(
- SocketPtr sp)
- {
- OSErr io;
- TCPiopb *pb;
-
- void sock_flush_out(SocketPtr);
- void sock_flush_in(SocketPtr);
-
- #if SOCK_TCP_DEBUG >= 2
- sock_print("sock_tcp_close ",sp);
- #endif
-
- if (!(pb= (TCPiopb *)sock_fetch_pb(sp)))
- return sock_err(ENOMEM);
-
- sock_flush_out(sp);
-
- /* close the stream */
- io = xTCPClose(pb,(TCPIOCompletionProc)(-1));
-
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: xTCPClose returns %d\n",io);
- #endif
-
- switch (io)
- {
- case noErr:
- case connectionClosing:
- break;
- case connectionDoesntExist:
- case connectionTerminated:
- break;
- case invalidStreamPtr:
- default:
- return(sock_err(io));
- }
-
- sock_flush_in(sp);
-
- /* destroy the stream */
- if ((io = xTCPRelease(pb)) != noErr)
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: xTCPRelease error %d\n",io);
- #endif
- return(sock_err(io));
- }
- /* check for errors from async writes etc */
- if (( sp->asyncerr != noErr ) && ( sp->asyncerr != connectionTerminated ))
- {
- #if SOCK_TCP_DEBUG >= 5
- dprintf("sock_tcp_close: asyncerr %d\n",sp->asyncerr);
- #endif
- return(sock_err(sp->asyncerr));
- }
- return(0);
- }
-
- /* int defaultSpin(spin_msg msg,long param) */
-
- static void sock_flush_out(SocketPtr sp) {
- while (xTCPWriteBytesLeft(sp)>0) {
- (*spinroutine)( SP_MISC,0L);
- }
- }
-
- static void sock_flush_in(SocketPtr sp) {
- TCPiopb *pb;
- rdsEntry rdsarray[TCP_MAX_WDS+1];
- int passcount;
- const int maxpass =4;
-
- if (!(pb = (TCPiopb *)sock_fetch_pb(sp)))
- return;
-
- for (passcount=0;passcount<maxpass;passcount++) {
- if (xTCPNoCopyRcv(pb,rdsarray,TCP_MAX_WDS,1,0)==noErr) {
- xTCPBufReturn(pb,rdsarray,0);
- (*spinroutine)( SP_MISC,0L);
- }
- else
- break;
- }
-
- if (passcount == maxpass) { /* remote side isn't being nice */
- (void)xTCPAbort(pb); /* then try again */
-
- for (passcount=0;passcount<maxpass;passcount++) {
- if (xTCPNoCopyRcv(pb,rdsarray,TCP_MAX_WDS,1,0)==noErr) {
- xTCPBufReturn(pb,rdsarray,0);
- (*spinroutine)( SP_MISC,0L);
- }
- else
- break;
- }
- }
- }
-
-
- #ifndef COMP_CODEWAR
- #pragma segment SOCK_RESIDENT
- #endif
- /*
- * Interrupt routines - MUST BE IN A RESIDENT SEGMENT! Most important to
- * MacApp programmers
- */
- pascal void sock_tcp_notify(
- StreamPtr tcpStream,
- unsigned short eventCode,
- Ptr userDataPtr,
- unsigned short terminReason,
- struct ICMPReport *icmpMsg)
- {
- #pragma unused (userDataPtr,terminReason,icmpMsg)
- register StreamHashEntPtr shep;
-
-
- shep = sock_find_shep(tcpStream);
- if ( shep )
- {
- SocketPtr sp = shep->socket;
-
- if ( eventCode == TCPClosing )
- {
- sp->sstate = SOCK_STATE_CLOSING;
- }
- else if ( eventCode == TCPTerminate )
- {
- sp->sstate = SOCK_STATE_UNCONNECTED;
- }
- }
- }
-
- static void sock_tcp_connect_done(TCPiopb *pb)
- {
- SocketPtr sp;
-
- sp = sock_find_shep(pb->tcpStream)->socket;
-
- if (pb->ioResult == noErr )
- {
- sp->sa.sin_addr.s_addr = pb->csParam.open.localHost;
- sp->sa.sin_port = pb->csParam.open.localPort;
- sp->peer.sin_addr.s_addr = pb->csParam.open.remoteHost;
- sp->peer.sin_port = pb->csParam.open.remotePort;
- sp->sstate = SOCK_STATE_CONNECTED;
- sp->asyncerr = noErr;
- }
- }
-
-
-
- static void sock_tcp_recv_done( TCPiopb *pb)
- {
- register readin;
- register SocketPtr sp;
-
- sp = sock_find_shep( pb->tcpStream )->socket;;
-
- if (pb->ioResult == noErr)
- {
- readin = pb->csParam.receive.rcvBuffLen;
- sp -> recvBuf += readin;
- sp -> recvd += readin;
- sp -> torecv -= readin;
- if ( sp -> torecv )
- {
- xTCPRcv(pb,sp->recvBuf,min(sp -> torecv,TCP_MAX_MSG),1,
- (TCPIOCompletionProc)sock_tcp_recv_done);
- }
- }
- }
-
-
- static void sock_tcp_send_done( TCPiopb *pb)
- {
- SocketPtr sp;
-
- sp = sock_find_shep(pb->tcpStream)->socket;
-
- switch(pb->ioResult)
- {
- case noErr:
- ((wdsEntry *)(pb->csParam.send.wdsPtr))->length = 0; /* mark it free */
- break;
-
- case ipNoFragMemErr:
- case connectionClosing:
- case connectionTerminated:
- case connectionDoesntExist:
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->asyncerr = ENOTCONN;
- break;
-
- case ipDontFragErr:
- case invalidStreamPtr:
- case invalidLength:
- case invalidWDS:
- default:
- sp->sstate = SOCK_STATE_UNCONNECTED;
- sp->asyncerr = pb->ioResult;
- break;
- }
-
- }
-
-